﻿using System;
using System.Collections.Generic;
using System.Linq;
using HK.Core.Extend;
using HK.Core.GUIEx.Protocol.Attribute;
using HK.Core.Serializable.Attribute;
using HK.Editor.Common;
using HK.Editor.GUIEx.Drag;
using HK.Editor.GUIEx.Drawer;
using HK.Editor.GUIEx.Property;
using HK.Editor.GUIEx.Protocol;
using HK.Editor.GUIEx.Protocol.Drag;
using HK.Editor.GUIEx.Protocol.Drawer;
using HK.Editor.GUIEx.Protocol.Selection;
using HK.Editor.GUIEx.Styles;
using HK.Editor.Serializable.Protocol.Drawer;
using HK.Editor.Utils;
using UnityEditor;
using UnityEditor.IMGUI.Controls;
using UnityEngine;

namespace HK.Editor.Serializable.Drawer
{
    
    /// <summary>
    /// Drawer - ListView
    /// </summary>
    [CustomPropertyDrawer(typeof(ListViewAttribute))]
    public class ListViewDrawer : GUIPropertyDrawer<ListViewAttribute>, IListViewDrawer
    {
        /// <summary>
        /// Element的Key Property
        /// </summary>
        public string ElementKey => SelfAttr?.ElementKey;
        
        /// <summary>
        /// Element可锁
        /// </summary>
        public virtual bool ElementLockable => true;
        
        /// <summary>
        /// 是否为数组标志位
        /// </summary>
        public bool IsArray
        {
            get
            {
                if (Pageable)
                {
                    return Pagination?.IsArray ?? false;
                }
                return ListProperty?.isArray ?? false;
            }
        }

        /// <summary>
        /// 数组大小
        /// </summary>
        public int TotalSize
        {
            get
            {
                if (Pageable)
                {
                    return Pagination?.TotalSize ?? 0;
                }
                return ListProperty?.arraySize ?? 0;
            }
        }

        /// <summary>
        /// 可见数量
        /// <para>* 分页的场合，为当前分页数量</para>
        /// </summary>
        public virtual int VisibleSize
        {
            get
            {
                if (Pageable)
                {
                    return Pagination?.VisibleSize ?? 0;
                }
                
                if (!Searching) return TotalSize;
                return SearchResult?.Count ?? 0;
            }
        }

        /// <summary>
        /// Footer可见标志位
        /// </summary>
        public virtual bool FooterVisible
        {
            get
            {
                if (Pageable) return Pagination?.FooterVisible ?? false;
                return Addable || Removable;
            }
        }

        /// <summary>
        /// 展开标志位
        /// </summary>
        public override bool IsExpanded
        {
            get => SelfProperty?.isExpanded ?? false;
            protected set
            {
                if(null == SelfProperty) return;
                SelfProperty.isExpanded = value;

                if (null != ListProperty)
                {
                    ListProperty.isExpanded = value;
                }
                ApplyChanged(SelfProperty);
            }
        }

#region Options

        /// <summary>
        /// 可排序
        /// </summary>
        public bool Sortable
        {
            get
            {
                if (!IsExpanded) return false;
                if (0 > VisibleSize) return false;
                return SelfAttr?.Sortable ?? false;
            }
        }
		
        /// <summary>
        /// 可检索
        /// </summary>
        public override bool Searchable 
        {
            get
            {
                if (!IsExpanded) return false;
                if (0 > VisibleSize) return false;
                return SelfAttr?.Searchable ?? false;
            }
        }

        /// <summary>
        /// 可分页
        /// </summary>
        public bool Pageable => SelfAttr?.Pageable ?? false;

        /// <summary>
        /// 取得分页选项
        /// </summary>
        /// <returns>分页选项</returns>
        private int GetPaginationOptions()
        {
            var options = (int)GUIOperateOptions.Pageable;

            if (Draggable)
            {
                options |= (int)GUIOperateOptions.Draggable;
            }

            if (Searchable)
            {
                options |= (int)GUIOperateOptions.Searchable;
            }

            if (Sortable)
            {
                options |= (int)GUIOperateOptions.Sortable;
            }

            if (MemberAsset)
            {
                options |= (int)GUIOperateOptions.MemberAsset;
            }

            if (MemberNoCaption)
            {
                options |= (int)GUIOperateOptions.MemberNoCaption;
            }

            if (MemberDraggable)
            {
                options |= (int)GUIOperateOptions.MemberDraggable;
            }

            if (MemberDistinct)
            {
                options |= (int)GUIOperateOptions.MemberDistinct;
            }

            if (Addable)
            {
                options |= (int)GUIOperateOptions.Addable;
            }

            if (Removable)
            {
                options |= (int)GUIOperateOptions.Removable;
            }

            if (Lockable)
            {
                options |= (int)GUIOperateOptions.Lockable;
            }
            
            return options;
        }

#endregion

        /// <summary>
        /// 初始化
        /// </summary>
        protected override void Init(Rect iRect)
        {
            ListSelection = GUIEx.Selection.ListSelection.Create(OnSelectionChanged);
            _dragRectsList = DragRectsList.Create(0);
            _elementRects = Array.Empty<Rect>();
            
            // 可分页
            if (Pageable)
            {
                var pageSize = SelfAttr?.PageSize ?? 30;
                var pagination = GUIEx.Pagination.Pagination.Create(pageSize);
                var paginationOptions = GetPaginationOptions();
                Pagination = SpPaginationDrawer.Create(ListProperty, pagination, ElementKey, 
                    OnPaginationSearchBtnClicked, DrawFromUnity, paginationOptions,
                    () =>
                    {
                        if(null == SelfProperty) return;

                        SelfProperty.serializedObject.ApplyModifiedProperties();
                        SelfProperty.serializedObject.Update();
                    });
            }
        }
        
#region SerializedProperty

        /// <summary>
        /// 列表Property
        /// </summary>
        public SerializedProperty ListProperty { get; private set; } = null;

        /// <summary>
        /// 初始化序列化Property信息
        /// </summary>
        /// <param name="iSelf">自身Property</param>
        /// <returns>true:OK; false:NG;</returns>
        protected override bool InitSerializedProperties(SerializedProperty iSelf)
        {
            if (!base.InitSerializedProperties(iSelf)) return false;

            ListProperty = SelfProperty.FindPropertyRelative("list");
            if (null == ListProperty)
            {
                this.Error("InitSerializedProperties():There is no property named list!");
                return false;
            }
            return true;
        }        
        
        /// <summary>
        /// 取得列表Element Property
        /// </summary>
        /// <param name="iIndex">索引</param>
        /// <returns>Element Property</returns>
        private SerializedProperty GetElementProperty(int iIndex)
        {
            if (!IsArray) return null;

            var childCount = VisibleSize;
            if (0 > iIndex || iIndex >= childCount)
            {
                this.Error("GetElementProperty():Invalid element index!(Index:{0}/{1})", iIndex, childCount);
                return null;
            }

            // 检索中
            if (Searching)
            {
                return SearchResult[iIndex].Target;
            }
            
            return ListProperty.GetArrayElementAtIndex(iIndex);
        }
        
        /// <summary>
        /// 移除Element
        /// </summary>
        /// <param name="iIndex">索引</param>
        private void RemoveElementByIndex(int iIndex)
        {
            if(!IsArray || 0 >= VisibleSize || null == ListProperty) return;
            
            // 检索中，则切换Property在总列表总的索引
            var targetIdx = iIndex;
            if (Searching)
            {
                var selectCapsule = SearchResult[iIndex];
                targetIdx = selectCapsule.Index;
            }
            
            if (targetIdx >= 0 && targetIdx < VisibleSize) 
            {
                var property = ListProperty.GetArrayElementAtIndex(iIndex);
                if (property.propertyType == SerializedPropertyType.ObjectReference && property.objectReferenceValue) 
                {
                    property.objectReferenceValue = null;
                }
                
                ListProperty.DeleteArrayElementAtIndex(targetIdx);
                ListSelection.Remove(iIndex);

                if (0 < VisibleSize) 
                {
                    ListSelection.Select(Mathf.Max(0, iIndex - 1));
                    // 若检索中
                    if (Searching)
                    {
                        SearchResult = DoSearchByKey(SearchKey);
                    }
                    _pressIndex = ListSelection.First;
                }
            }
			
            // 重置列表Element标题
            RefreshElementCaptions();
        }
        
#endregion

#region Content

        /// <summary>
        /// 标题
        /// </summary>
        private GUIContent _emptyLabelContent = null;

        /// <summary>
        /// 按钮 - 检索
        /// <para>* Icon Only</para>
        /// </summary>
        protected GUIContent SearchIconBtnContent { get; private set; } = null;

        /// <summary>
        /// 按钮 - 取消检索
        /// <para>* Icon Only</para>
        /// </summary>
        protected GUIContent SearchCancelIconBtnContent { get; private set; } = null;		

        /// <summary>
        /// 按钮 - 检索
        /// </summary>
        protected GUIContent SearchBtnContent { get; private set; } = null;
        
        /// <summary>
        /// 锁定按钮 - IconOnly
        /// </summary>
        protected GUIContent LockIconBtnContent { get; private set; } = null;
        
        /// <summary>
        /// 解锁按钮 - IconOnly
        /// </summary>
        protected GUIContent UnLockIconBtnContent { get; private set; } = null;

        /// <summary>
        /// 初始化Content
        /// </summary>
        /// <param name="iAttr">Attribute</param>
        /// <param name="iProperty">Property</param>
        /// <param name="iLabel">默认标题</param>
        protected override void InitContents(ListViewAttribute iAttr, SerializedProperty iProperty, GUIContent iLabel)
        {
            base.InitContents(iAttr, iProperty, iLabel);
            
            var emptyLabel = IsArray ? "List is empty!" : "This is not list type!";
            _emptyLabelContent = UtilsGUIEx.CreateGuiContent(emptyLabel);
            
            // 加锁/解锁
            LockIconBtnContent = UtilsGUIEx.CreateGuiContentWithIcon("", EditorConst.IconLock);
            UnLockIconBtnContent = UtilsGUIEx.CreateGuiContentWithIcon("", EditorConst.IconUnLock);
            
            // 检索
            SearchIconBtnContent = UtilsGUIEx.CreateGuiContentWithIcon("", EditorConst.IconBrowse);
            SearchCancelIconBtnContent = UtilsGUIEx.CreateGuiContentWithIcon("", EditorConst.IconDisable);
            SearchBtnContent = UtilsGUIEx.CreateGuiContentWithIcon("检索", EditorConst.IconBrowse);
        }
        
        /// <summary>
        /// 重置标题
        /// </summary>
        /// <param name="iAttr">Attribute</param>
        /// <param name="iProperty">Property</param>
        /// <param name="iLabel">默认标题</param>
        /// <returns>标题</returns>
        protected override GUIContent ResetCaption(ListViewAttribute iAttr, SerializedProperty iProperty, GUIContent iLabel)
        {
            var captionTmp = base.ResetCaption(iAttr, iProperty, iLabel);
            if (null == captionTmp) return null;

            captionTmp.text = Searching? $"{captionTmp.text}(Count:{VisibleSize}/{TotalSize})" : $"{captionTmp.text}(Count:{TotalSize})";
            return captionTmp;
        }
        
        /// <summary>
        /// 重置标题
        /// </summary>
        /// <returns>标题</returns>
        private GUIContent ResetCaption()
        {
            var captionTmp = Caption;
            if (null == captionTmp) return null;

            captionTmp.text = Searching? $"{SelfAttr.Caption}(Count:{VisibleSize}/{TotalSize})" : $"{SelfAttr.Caption}(Count:{TotalSize})";
            return captionTmp;
        }
        
        private Dictionary<int, GUIContent> _childContents = new Dictionary<int, GUIContent>();

        /// <summary>
        /// 刷新生成标题列表
        /// </summary>
        private void RefreshElementCaptions()
        {
            _childContents.Clear();
            if (!IsArray || 0 >= VisibleSize)
            {
                return;
            }

            GetVisibleRange(out var oStartIndex, out var oEndIndex);
            for (var idx = oStartIndex; idx < oEndIndex; ++idx)
            {
                var childProperty = GetElementProperty(idx);
                if(null == childProperty) continue;
                GetElementCaption(idx, childProperty);
            }
        }
        
        /// <summary>
        /// 取得Element标题
        /// </summary>
        /// <param name="iIndex">Element索引</param>
        /// <param name="iChildProperty">Child Property</param>
        /// <returns>Element标题</returns>
        protected virtual GUIContent GetElementCaption(int iIndex, SerializedProperty iChildProperty)
        {
            GUIContent caption = null;
            if (!_childContents.TryGetValue(iIndex, out caption))
            {
                if (!string.IsNullOrEmpty(ElementKey))
                {
                    var keyProperty = iChildProperty.FindPropertyRelative(ElementKey);
                    var captionTxtTmp = keyProperty.stringValue;
                    if (string.IsNullOrEmpty(captionTxtTmp))
                    {
                        captionTxtTmp = "Element";
                    }
                    caption = UtilsGUIEx.CreateGuiContent($"({iIndex}){captionTxtTmp}");
                    _childContents.Add(iIndex, caption);
                }
                else
                {
                    caption = UtilsGUIEx.CreateGuiContent($"({iIndex})Element");
                    _childContents.Add(iIndex, caption);
                }
            }
            else
            {
                if (null == caption)
                {
                    caption = UtilsGUIEx.CreateGuiContent($"({iIndex})Element");
                }
                _childContents[iIndex] = caption;
            }
            
            return caption;
        }
        
#endregion

#region Rect

        /// <summary>
        /// 高度 : 空列表高度
        /// </summary>
        private static readonly float EmptyListHeight = 40.0f;

        /// <summary>
        /// 按钮宽度 - 检索那妞
        /// </summary>
        private static readonly float _searchBtnWidth = BtnWidthShort;
        
        /// <summary>
        /// 高度 - Footer
        /// </summary>
        protected override float FooterHeight
        {
            get
            {
                if (!Pageable) return HeaderHeight;
                
                return Pagination?.GetFooterHeight() ?? HeaderHeight;
            }
        }

        /// <summary>
        /// 检索部高度
        /// </summary>
        protected virtual float SearchBarHeight => HeaderHeight;
        
        /// <summary>
        /// 取得Property的高度
        /// </summary>
        /// <param name="iProperty">Property</param>
        /// <param name="iLabel">文本</param>
        /// <returns>Property的高度</returns>
        public override float GetPropertyHeight(SerializedProperty iProperty, GUIContent iLabel)
        {
            var totalHeight = 0.0f;
            // 分页Bar
            if (Pageable)
            {
                totalHeight = HeaderHeight;
                if (!iProperty.isExpanded)
                {
                    TotalHeight = totalHeight;
                    return TotalHeight;
                }
                
                totalHeight += Pagination?.CalcTotalHeight() ?? HeaderHeight;
            }
            else
            {            
                totalHeight = base.GetPropertyHeight(iProperty, iLabel);
                if (!iProperty.isExpanded)
                {
                    TotalHeight = totalHeight;
                    return TotalHeight;
                }
                
                // 检索Bar
                if (Searchable && Searching)
                {
                    totalHeight += SearchBarHeight + 1;
                }

                if (FooterVisible)
                {
                    totalHeight += FooterHeight + 6;
                }
                else
                {
                    totalHeight += 6;
                }
            }
            
            TotalHeight = totalHeight;
            return TotalHeight; 
        }
        
        /// <summary>
        /// 计算子节点元素的总共高度
        /// </summary>
        /// <param name="iParent">父节点Property</param>
        /// <param name="oValidCount">有效个数</param>
        /// <returns>子节点元素的总共高度</returns>
        protected override float CalcElementsTotalHeight(SerializedProperty iParent, out int oValidCount)
        {
            oValidCount = 0;
            var elementTotalHeight = 0.0f;
            if (!IsArray || null == ListProperty) return elementTotalHeight;

            if (0 >= VisibleSize)
            {
                elementTotalHeight = EmptyListHeight;
            }
            else
            {
                GetVisibleRange(out var oStartIndex, out var oEndIndex);
                // 检索中
                if (Searching)
                {
                    for (var idx = oStartIndex; idx < oEndIndex; ++idx)
                    {
                        var childCapsule = SearchResult[idx];
                        elementTotalHeight += GetElementHeight(idx, childCapsule.Target) + 1;
                        ++oValidCount;
                    }
                }
                else
                {
                    for (var idx = oStartIndex; idx < oEndIndex; ++idx)
                    {
                        var childProperty = ListProperty.GetArrayElementAtIndex(idx);
                        elementTotalHeight += GetElementHeight(idx, childProperty) + 1;
                        ++oValidCount;
                    }
                }
            }
            
            return elementTotalHeight;
        }
        
        /// <summary>
        /// 取得Element高度
        /// </summary>
        /// <param name="iIndex">Element索引</param>
        /// <param name="iElement">Element</param>
        /// <returns>Element高度</returns>
        private float GetElementHeight(int iIndex, SerializedProperty iElement)
        {
            var elementHeight = GetPropertyHeight(iElement, GetElementCaption(iIndex, iElement), iElement.isExpanded);
            if (!iElement.isExpanded)
            {
                elementHeight += VerticalSpacing;
            }
            else
            {
                elementHeight -= 1;
            }

            var expandedInfo = GetExpandedInfo(iElement);
            return elementHeight;
        }

        private static string GetDepthIntent(int iDepthLen)
        {
            if (0 >= iDepthLen) return null;
            var str = string.Empty;
            for (var idx = 0; idx < iDepthLen; ++idx)
            {
                str = string.IsNullOrEmpty(str) ? "    " : $"{str}    ";
            }
            return str;
        }

        private string GetExpandedInfo(SerializedProperty iElement)
        {
            
            var copy = iElement.Copy();
            var startDepth = copy.depth;
            var detail = $"{copy.displayName}:isExpanded - {copy.isExpanded}";
            
            var end = copy.GetEndProperty();
            var nextVisible = copy.NextVisible(true);
            while (nextVisible && !SerializedProperty.EqualContents(copy, end))
            {
                var depthLen = copy.depth - startDepth;
                depthLen = Mathf.Max(0, depthLen);
                var depthIntent = GetDepthIntent(depthLen);
                
                detail = $"{detail}\n{depthIntent}{copy.name}:isExpanded - {copy.isExpanded}";
                nextVisible = copy.NextVisible(true);
            }

            return detail;
        }

        /// <summary>
        /// 各个Element的矩形区域
        /// </summary>
        private Rect[] _elementRects = null;

        /// <summary>
        /// 取得Elements列表总得包围盒
        /// </summary>
        /// <returns>Elements列表总得包围盒</returns>
        private Rect GetElementsTotalBound()
        {
            var totalRect = Rect.zero;
            if(null == _elementRects || 0 >= _elementRects.Length) return totalRect;

            var count = _elementRects.Length;
            for (var idx = 0; idx < count; ++idx)
            {
                if (0 == idx)
                {
                    totalRect = _elementRects[idx];
                }
                else
                {
                    totalRect.yMax = Mathf.Max(totalRect.yMax, _elementRects[idx].yMax);
                }
            }
            totalRect.yMax += VerticalSpacing * 2;
            return totalRect;
        }
        
        /// <summary>
        /// 更新Element的绘制矩形区域
        /// </summary>
        /// <param name="iRect">矩形区域</param>
        /// <param name="iEvent">事件</param>
        private void UpdateElementRects(Rect iRect, Event iEvent) 
        {

            // resize array if elements changed
            var len = VisibleSize;
			
            // 长度有变化，则重置数组大小
            if (len != _elementRects.Length) 
            {
                Array.Resize(ref _elementRects, len);
            }

            // 重新绘制
            if (EventType.Repaint == iEvent.type) 
            {

                //start rect
                var elementRect = iRect;
                elementRect.yMin = elementRect.yMax = iRect.yMin + 1;
                //elementRect.y += VerticalSpacing;
                //var spacing = VerticalSpacing;
				
                // TODO:追加分页处理
                // 取得分页可视范围
                if(!GetVisibleRange(out var oStartIndex, out var oEndIndex)) return;

                // 遍历
                for (var idx = oStartIndex; idx < oEndIndex; ++idx) 
                {
                    var element = GetElementProperty(idx);
					if(null == element) continue;
                    
                    elementRect.y = elementRect.yMax;
                    elementRect.height = GetElementHeight(idx, element);
                    _elementRects[idx] = elementRect;
                    elementRect.yMax += 1;
					
                }
            }
        }
        
        /// <summary>
        /// 取得指定位置的Element的索引
        /// </summary>
        /// <param name="iPosition">位置</param>
        /// <returns>Element的索引</returns>
        private int GetGetElementIndexByPos(Vector2 iPosition) 
        {
            // 取得可视范围
            if (!GetVisibleRange(out var oStartIndex, out var oEndIndex)) return -1;
            
            // 遍历
            for (var idx = oStartIndex; idx < oEndIndex; ++idx) 
            {
                var rect = _elementRects[idx];
                if (rect.Contains(iPosition) || (idx == 0 && iPosition.y <= rect.yMin) || (idx == oEndIndex - 1 && iPosition.y >= rect.yMax)) 
                {
                    return idx;
                }
            }

            return -1;
        }

#endregion
        
#region Selection
        
        /// <summary>
        /// 拖拽之前列表选中信息
        /// </summary>
        private IListSelection _prevListSelection = null;
        /// <summary>
        /// 列表选中情报
        /// </summary>
        public IListSelection ListSelection { get; private set; } = null;
        
        /// <summary>
        /// 多个可选标志位
        /// <para>* true:可同时选中多个对象; false:不可选中多个;</para>
        /// </summary>
        private bool _multipleSelection = false;
        
        /// <summary>
        /// 校验是否能被选中
        /// <para>* 仅仅校验Element的索引在不在合法范围内</para>
        /// </summary>
        /// <param name="iIndex">Element索引</param>
        /// <returns>true:能被选中; false:反之;</returns>
        private bool CanSelect(int iIndex) 
        {
            return iIndex >= 0 && iIndex < VisibleSize;
        }
        
        /// <summary>
        /// 判断指定位置是否在Element范围之内
        /// </summary>
        /// <param name="iPosition">位置</param>
        /// <param name="iIndex">Element索引</param>
        /// <returns>true:在Element范围内; false:反之;</returns>
        private bool IsPositionWithinElement(Vector2 iPosition, int iIndex) 
        {
            return CanSelect(iIndex) && _elementRects[iIndex].Contains(iPosition);
        }		
        
        /// <summary>
        /// 判断鼠标左键/中键按下？
        /// </summary>
        /// <param name="iEvent">Event</param>
        /// <returns>true:按下; false:未按下;</returns>
        private bool IsMouseLeftOrMidBtnDown(Event iEvent) 
        {
            // 鼠标左键/中键按下
            return iEvent.button == 0 || iEvent.button == 2;
        }
        
        /// <summary>
        /// 校验是否能被选中
        /// </summary>
        /// <param name="iPosition">位置</param>
        /// <returns>true:能被选中; false:反之;</returns>
        private bool CanSelect(Vector2 iPosition) 
        {
            return ListSelection.Length > 0 && ListSelection.Any(iIndex => IsPositionWithinElement(iPosition, iIndex));
        }

        /// <summary>
        /// 列表Element选中回调
        /// </summary>
        public ListElementSelected<SerializedProperty> ElementSelected { get; private set; } = null;
        
        /// <summary>
        /// 选中变更事件
        /// </summary>
        /// <param name="iIndex">Element索引</param>
        /// <param name="iSelected">选中/没选中</param>
        private void OnSelectionChanged(int iIndex, bool iSelected)
        {
            SerializedProperty targetProperty = null;
            
            if(0 > iIndex || iIndex >= TotalSize) return;
            targetProperty = ListProperty.GetArrayElementAtIndex(iIndex);
			
            if(null == targetProperty) return;
            ElementSelected?.Invoke(iIndex, targetProperty, iSelected);
        }

        /// <summary>
        /// 取得游侠范围
        /// </summary>
        /// <param name="oStartIndex">Element开始索引</param>
        /// <param name="oEndIndex">Element结束索引</param>
        /// <returns>true:OK; false:NG;</returns>
        protected virtual bool GetVisibleRange(out int oStartIndex, out int oEndIndex)
        {
            oStartIndex = 0;
            oEndIndex = 0;
            if (!IsArray) return false;
            if (0 >= VisibleSize) return true;
            
            // 若是分页
            if (Pageable)
            {
                return Pagination.GetVisibleRange(VisibleSize, out oStartIndex, out oEndIndex);
            }
            
            oEndIndex = VisibleSize;
            return true;
        }
        
        /// <summary>
        /// 设置选中
        /// </summary>
        /// <param name="iIndex">选中Element索引</param>
        /// <param name="iSetKeyboardControl">设置Keyboard</param>
        /// <param name="iEvent">Event</param>
        private void DoSelection(int iIndex, bool iSetKeyboardControl, Event iEvent) 
        {

            // append selections based on action, this may be a additive (ctrl) or range (shift) selection
            if (_multipleSelection) 
            {
                ListSelection.AppendWithAction(_pressIndex = iIndex, iEvent);
            }
            else 
            {
                ListSelection.Select(_pressIndex = iIndex);
            }

            // 回调
            // onSelectCallback?.Invoke(this);

            if (Draggable) 
            {
                _dragging = false;
                _dragPosition = _pressPosition = iEvent.mousePosition.y;
                if (!GetVisibleRange(out var oStartIndex, out var oEndIndex))
                {
                    iEvent.Use();
                    return;
                }
                
                UpdateListDragRects(_dragPosition, oStartIndex, oEndIndex);

                // 移除开始与结束区间以外的信息
                ListSelection.Trim(oStartIndex, oEndIndex);
                _prevListSelection = ListSelection.Clone();

                GUIUtility.hotControl = ControlId;
            }

            // 设置Keyboard
            if (iSetKeyboardControl) 
            {
                GUIUtility.keyboardControl = ControlId;
            }

            iEvent.Use();
        }

#endregion

#region Drag

        /// <summary>
        /// 拖拽中
        /// </summary>
        private bool _dragging = false;

        /// <summary>
        /// 拖拽位置
        /// </summary>
        private float _dragPosition = 0.0f;
		
        /// <summary>
        /// 鼠标按下位置
        /// <para>* 仅仅记录纵方向的位置。即:y坐标</para>
        /// </summary>
        private float _pressPosition = 0.0f;
        private int _pressIndex = 0;
        
        /// <summary>
        /// 拖拽方向
        /// <para>* 1 : 相对当前Element往后</para>
        /// <para>* -1 : 相对当前Element往前</para>
        /// </summary>
        private int _dragDirection = 0;

        /// <summary>
        /// 拖拽元素列表
        /// </summary>
        private IDragRectsList _dragRectsList = null;
        
        /// <summary>
        /// 更新拖拽位置
        /// </summary>
        /// <param name="iPosition">位置</param>
        /// <param name="iBounds">拖拽范围</param>
        /// <param name="iDragRectsList">列表拖拽区域</param>
        /// <returns>true:有拖拽; false:无拖拽;</returns>
        private bool UpdateDragPosition(Vector2 iPosition, Rect iBounds, IDragRectsList iDragRectsList) 
        {
            var startIndex = 0;
            var endIndex = ListSelection.Length - 1;

            var minOffset = iDragRectsList[startIndex].DragOffset;
            var maxOffset = iDragRectsList[endIndex].Rect.height - iDragRectsList[endIndex].DragOffset;

            _dragPosition = Mathf.Clamp(iPosition.y, iBounds.yMin + minOffset, iBounds.yMax - maxOffset);

            if (Mathf.Abs(_dragPosition - _pressPosition) > 1.0f) 
            {
                _dragPosition = (int)Mathf.Sign(_dragPosition - _pressPosition);
                return true;
            }

            return false;
        }
        
        /// <summary>
        /// 更新列表拖拽区域信息
        /// </summary>
        /// <param name="iDragPosition">拖拽坐标</param>
        /// <param name="iStartIndex">开始索引</param>
        /// <param name="iEndIndex">结束索引</param>
        private void UpdateListDragRects(float iDragPosition, int iStartIndex, int iEndIndex) 
        {
            if(null == ListProperty) return;
            
            _dragRectsList.Resize(iStartIndex, iEndIndex - iStartIndex);
            for (var i = iStartIndex; i < iEndIndex; ++i) 
            {
                var property = ListProperty.GetArrayElementAtIndex(i);
                var elementRect = _elementRects[i];
                var dragElement = new DragElement
                {
                    Property = property,
                    DragOffset = _dragPosition - elementRect.y,
                    Rect = elementRect,
                    DesiredRect = elementRect,
                    Selected = ListSelection.Contains(i),
                    StartIndex = i
                };
                _dragRectsList[i - iStartIndex] = dragElement;
            }

            // 根据索引重排序
            _dragRectsList.SortByIndex();
        }
        
        /// <summary>
        /// 重现排序
        /// </summary>
        /// <param name="iDirection">方向(1:向后移动; -1:向前移动;)</param>
        /// <param name="offset"></param>
        /// <param name="sortList"></param>
        private void ReorderDraggedElements(int iDirection, int offset, System.Action sortList) 
        {
            if(null == ListProperty) return;
            
            // save the current expanded states on all elements. I don't see any other way to do this
            // MoveArrayElement does not move the foldout states, so... fun.
            _dragRectsList.RecordState();

            // 排序
            sortList?.Invoke();

            ListSelection.Sort((iA, iB) => {

                var d1 = _dragRectsList.GetIndexFromSelection(iA);
                var d2 = _dragRectsList.GetIndexFromSelection(iB);
                return iDirection > 0 ? d1.CompareTo(d2) : d2.CompareTo(d1);
            });

            // swap the selected elements in the List
            var s = ListSelection.Length;
            while (--s > -1) 
            {
                var newIndex = _dragRectsList.GetIndexFromSelection(ListSelection[s]);
                var listIndex = newIndex + offset;
                ListSelection[s] = listIndex;
                ListProperty.MoveArrayElement(_dragRectsList[newIndex].StartIndex, listIndex);
            }

            // restore expanded states on items
            // 恢复展开信息
            _dragRectsList.RestoreState(ListProperty);

            // apply and update
            // 应用重排序信息
            ApplyReorder();
        }

#endregion

#region Lock

        /// <summary>
        /// Element枷锁状态
        /// <para>* Key : Element索引</para>
        /// <para>* Value : 锁定/未锁定标志位</para>
        /// </summary>
        private Dictionary<int, bool> _elementsLockStates = new Dictionary<int, bool>();

        /// <summary>
        /// 判断指定索引的Element是否被锁定
        /// </summary>
        /// <param name="iIndex">Element索引</param>
        /// <returns>true:锁定; false:未锁定;</returns>
        private bool IsElementLocked(int iIndex)
        {
            if (-1 >= iIndex || iIndex >= TotalSize) return false;
            
            // 若尚未存在，则默认未锁定状态
            if (0 >= _elementsLockStates.Count)
            {
                SetElementLockState(iIndex, true);
                return true;
            }
            if (!_elementsLockStates.TryGetValue(iIndex, out var oLocked))
            {
                SetElementLockState(iIndex, true);
                return true;
            }
            
            return oLocked;
        }

        /// <summary>
        /// 设定Element的锁定状态
        /// </summary>
        /// <param name="iIndex">Element索引</param>
        /// <param name="iLocked">true:锁定; false:未锁定;</param>
        private void SetElementLockState(int iIndex, bool iLocked)
        {
            if (-1 >= iIndex || iIndex >= TotalSize) return;

            if (0 >= _elementsLockStates.Count)
            {
                _elementsLockStates.Add(iIndex, iLocked);
                return;
            }
            
            _elementsLockStates[iIndex] = iLocked;
        }

#endregion

#region Sortable
        
        /// <summary>
        /// 排序按钮点击回调
        /// </summary>
        /// <param name="iDescending">true:降序; false:升序;</param>
        private void OnSortBtnClicked(bool iDescending)
        {
            // 分页模式
            if (Pageable)
            {
                if (null != Pagination)
                {
                    Pagination.Sort(!iDescending);
                }
                return;
            }
            
            if(!IsArray || 0 >= VisibleSize) return;
                    
            // 排序
            PropertyArraySort.SortOnProperty(ListProperty, VisibleSize, iDescending, ElementKey);
            
            // 应用
            ApplyReorder();
            // 刷新标题
            RefreshElementCaptions();
            
            HandleUtility.Repaint();
        }

        /// <summary>
        /// 应用重排序
        /// </summary>
        private void ApplyReorder() => ApplyChanged(ListProperty);

#endregion
        
#region SearchBar

        /// <summary>
        /// 检索Bar
        /// </summary>
        protected SearchField SearchBar { get; private set; } = null;

        /// <summary>
        /// 检索Key
        /// </summary>
        protected string SearchKey { get; private set; } = null;

        private bool _showSearchBar = false;
        /// <summary>
        /// 下那是检索Bar
        /// </summary>
        private bool ShowSearchBar
        {
            get
            {
                if (Pageable)
                {
                    return Pagination?.SearchBarVisible ?? false;
                }

                return _showSearchBar;
            }
            set
            {
                if (Pageable)
                {
                    if(null == Pagination) return;
                    Pagination.ShowSearchBar(value);
                    return;
                }
                _showSearchBar = value;
            }
        }

        private bool _searching = false;
        /// <summary>
        /// 检索中标志位
        /// </summary>
        private bool Searching
        {
            get
            {
                if (Pageable)
                {
                    return Pagination?.Searching ?? false;
                }

                return _searching;
            }
            set
            {
                if (Pageable)
                {
                    return;
                }
                _searching = value;
            }
        }

        /// <summary>
        /// 检索列表
        /// </summary>
        protected List<SearchCapsule<SerializedProperty>> SearchResult { get; set; } = null;
        
        /// <summary>
        /// 执行检索
        /// </summary>
        /// <param name="iSearchKey">检索Key</param>
        private List<SearchCapsule<SerializedProperty>> DoSearchByKey(string iSearchKey)
        {
            if (string.IsNullOrEmpty(ElementKey) || !IsArray || 0 >= TotalSize) return null;

            if (string.IsNullOrEmpty(iSearchKey))
            {
                Searching = false;
                return null;
            }
            
            var searchResult = new List<SearchCapsule<SerializedProperty>>();
            var count = TotalSize;
            for (var idx = 0; idx < count; idx++)
            {
                var childProperty = ListProperty.GetArrayElementAtIndex(idx);
                var keyProperty = childProperty?.FindPropertyRelative(ElementKey);
                if(keyProperty == null) continue;

                var keyValue = keyProperty.stringValue;
                if(string.IsNullOrEmpty(keyValue)) continue;

                if (!keyValue.ToLower().Contains(iSearchKey.ToLower())) continue;
                var searchCapsule = new SearchCapsule<SerializedProperty> { Index = idx, Target = childProperty };
                searchResult.Add(searchCapsule);
            }
            
            return searchResult;
        }

#endregion
        
#region Pagination

        /// <summary>
        /// 分页面板
        /// </summary>
        public IPaginationDrawer Pagination { get; private set; } = null;

        /// <summary>
        /// 分页面板检索按钮点击事件
        /// </summary>
        /// <param name="iSearchKey">检索Key</param>
        private void OnPaginationSearchBtnClicked(string iSearchKey)
        {
            ResetCaption();
        }

#endregion
        
#region Events

        /// <summary>
        /// 展开
        /// </summary>
        /// <param name="iSelfProperty">自身Property</param>
        /// <param name="iIsExpanded">展开/缩进</param>
        protected override void ExpandChildren(SerializedProperty iSelfProperty, bool iIsExpanded)
        {
            if(null == iSelfProperty) return;
            iSelfProperty.isExpanded = iIsExpanded;
            
            // 非数组元素
            var copy = iSelfProperty.Copy();
            var end = copy.GetEndProperty();
            
            var nextVisible = copy.NextVisible(true);
            while (nextVisible && !SerializedProperty.EqualContents(copy, end))
            {
                copy.isExpanded = iIsExpanded;
                nextVisible = copy.NextVisible(false);
            }
        }
        
        /// <summary>
        /// 展开
        /// </summary>
        /// <param name="iChildProperty">Property</param>
        /// <param name="iIsExpanded">展开/缩进</param>
        private void ExpandChildrenOfChild(SerializedProperty iChildProperty, bool iIsExpanded)
        {
            if(null == iChildProperty) return;
            iChildProperty.isExpanded = iIsExpanded;
            
            // 非数组元素
            var copy = iChildProperty.Copy();
            var end = copy.GetEndProperty();
            
            var nextVisible = copy.NextVisible(true);
            while (nextVisible && !SerializedProperty.EqualContents(copy, end))
            {
                copy.isExpanded = iIsExpanded;
                nextVisible = copy.NextVisible(false);
            }
        }
        
        /// <summary>
        /// 删除Element按钮点击时间
        /// </summary>
        private void OnDelElementBtnClicked()
        {
            if (!IsArray || null == ListProperty || 0 >= VisibleSize) return;

            var selectIndex = ListSelection.First;
            selectIndex = 0 >= selectIndex ? 0 : selectIndex;
            
            RemoveElementByIndex(selectIndex);
        }
        
        /// <summary>
        /// 追加Element按钮点击时间
        /// </summary>
        private void OnAddElementBtnClicked()
        {
            if (!IsArray || null == ListProperty) return;
            
            // 自增一个Element
            ListProperty.arraySize++;
            if (1 < ListProperty.arraySize)
            {
                ListProperty.MoveArrayElement(ListProperty.arraySize - 1, 0);
            }
            
            ListSelection.Select(0);
            
            // 重置列表Element标题
            RefreshElementCaptions();
        }
        
        /// <summary>
        /// 挂接右键菜单 - 多选
        /// <para>* 为选中Element后，鼠标右键菜单</para>
        /// </summary>
        /// <param name="iEvent">Event</param>
        private void HandleMultipleRightClick(Event iEvent) 
        {
            var menu = new GenericMenu();
            // 可还原
            if (ListSelection.CanRevert(ListProperty)) 
            {
                menu.AddItem(new GUIContent("Revert Values to Prefab"), false, ListSelection.RevertValues, ListProperty);
                menu.AddSeparator(string.Empty);
            }

            // 挂接右键共享菜单
            HandleSharedRightClick(iEvent, menu, ListProperty,
                "Duplicate Array Elements", 
                "Delete Array Elements", 
                "Move Array Elements");
        }
        
        /// <summary>
        /// 挂接右键共享菜单
        /// </summary>
        /// <param name="iEvent">Event</param>
        /// <param name="iMenu">右键菜单</param>
        /// <param name="iListProperty">List Property</param>
        /// <param name="iDuplicateLabel">复制Element标题</param>
        /// <param name="iDeleteLabel">删除Element标题</param>
        /// <param name="iMoveLabel">移动Element标题</param>
        protected virtual void HandleSharedRightClick(
            Event iEvent, GenericMenu iMenu, SerializedProperty iListProperty, string iDuplicateLabel, 
            string iDeleteLabel, string iMoveLabel) 
        {

            iMenu.AddItem(new GUIContent(iDuplicateLabel), false, OnMenuItemClickedOfDuplicate, iListProperty);
            iMenu.AddItem(new GUIContent(iDeleteLabel), false, OnMenuItemClickedOfDelete, iListProperty);

            // TODO:分页列表
            // if (Pageable) 
            // {
            //     var pages = pagination.GetPageCount(VisibleCount);
            //     if (pages > 1) {
            //
            //         for (var idx = 0; idx < pages; ++idx) {
            //
            //             var pageLabel = $"{iMoveLabel}/Page {idx + 1}";
            //             iMenu.AddItem(new GUIContent(pageLabel), idx == pagination.Index, DrawElementRightClickMenu, idx);
            //         }
            //     }
            // }

            // 显示右键列表
            iMenu.ShowAsContext();
            iEvent.Use();
        }
        
        /// <summary>
        /// 挂接复制事件
        /// </summary>
        /// <param name="iProperty">欲复制的Property</param>
        private void OnMenuItemClickedOfDuplicate(object iProperty) 
        {
            ListSelection.Duplicate(iProperty as SerializedProperty);
        }
        
        /// <summary>
        /// 挂接删除事件
        /// </summary>
        /// <param name="iProperty">欲删除的Property</param>
        private void OnMenuItemClickedOfDelete(object iProperty) 
        {
            ListSelection.Delete(iProperty as SerializedProperty);
        }
        
        /// <summary>
        /// 列表选中处理 - 前处理
        /// </summary>
        /// <param name="iRect">绘制矩形区域</param>
        /// <param name="iEvent">Event</param>
        private void HandlePreSelection(Rect iRect, Event iEvent) 
        {
            if (iEvent.type == EventType.MouseDrag && Draggable && GUIUtility.hotControl == ControlId) 
            {
                if (ListSelection.Length > 0 && UpdateDragPosition(iEvent.mousePosition, iRect, _dragRectsList)) 
                {
                    GUIUtility.keyboardControl = ControlId;
                    _dragging = true;
                }

                iEvent.Use();
            }
        }
        
        /// <summary>
        /// 列表选中处理 - 后处理
        /// </summary>
        /// <param name="iRect">绘制矩形区域</param>
        /// <param name="iEvent">Event</param>
        private void HandlePostSelection(Rect iRect, Event iEvent) 
		{

			switch (iEvent.GetTypeForControl(ControlId)) 
			{
				// 鼠标按下
				case EventType.MouseDown:

					if (iRect.Contains(iEvent.mousePosition) && IsMouseLeftOrMidBtnDown(iEvent)) 
					{
						// 取得选中Element的索引
						var index = GetGetElementIndexByPos(iEvent.mousePosition);
						if (CanSelect(index)) 
						{
							// 当前Keyboard无焦点，或者当前焦点目标为当前对象，或者鼠标中间按下
							DoSelection(index, GUIUtility.keyboardControl == 0 || GUIUtility.keyboardControl == ControlId || iEvent.button == 2, iEvent);
						}
						else 
						{
							// 清空选中信息
							ListSelection.Clear();
						}

						HandleUtility.Repaint();
					}

					break;

				// 鼠标抬起
				case EventType.MouseUp:

					// 不可拖拽
					if (!Draggable) 
					{
						// select the single object if no selection modifier is being performed
						// 选中当前按下所选中Element的索引
                        ListSelection.SelectWhenNoAction(_pressIndex, iEvent);
					}
					// 当前对象被选中
					else if (GUIUtility.hotControl == ControlId) 
					{
						iEvent.Use();
						// 拖拽中
						if (_dragging) 
						{

                            _dragging = false;
							//move elements in list
							ReorderDraggedElements(_dragDirection, _dragRectsList.StartIndex, () => _dragRectsList.SortByPosition());
						}
						else 
						{

							// if we didn't drag, then select the original pressed object
                            ListSelection.SelectWhenNoAction(_pressIndex, iEvent);
						}

						GUIUtility.hotControl = 0;
					}

					HandleUtility.Repaint();

					break;

				// 键盘按键按下
				case EventType.KeyDown:

					if (GUIUtility.keyboardControl == ControlId) 
					{
						// 向下箭头按下
						if (iEvent.keyCode == KeyCode.DownArrow && !_dragging) 
						{
                            ListSelection.Select(Mathf.Min(ListSelection.Last + 1, VisibleSize - 1));
							iEvent.Use();
						}
						// 向上箭头按下
						else if (iEvent.keyCode == KeyCode.UpArrow && !_dragging) 
						{

                            ListSelection.Select(Mathf.Max(ListSelection.Last - 1, 0));
							iEvent.Use();
						}
						// Esc键按下
						else if (iEvent.keyCode == KeyCode.Escape && GUIUtility.hotControl == ControlId) 
						{

							GUIUtility.hotControl = 0;
							if (_dragging) 
							{
                                _dragging = false;
                                ListSelection = _prevListSelection;
							}

							iEvent.Use();
						}
					}

					break;
			}
		}
        
#endregion

#region Draw
        
        /// <summary>
        /// 绘制GUI
        /// </summary>
        /// <param name="iRect">绘制矩形区域</param>
        /// <param name="iProperty">Property</param>
        /// <param name="iLabel">标题</param>
        public override void OnGUI(Rect iRect, SerializedProperty iProperty, GUIContent iLabel)
        {
            // 初始化
            InitSerializedProperties(iProperty);
            InitContents(SelfAttr, SelfProperty, iLabel);
            
            if (!Initialized)
            {
                Init(iRect);
                Initialized = true;
            }
            
            // 控件Id
            ControlId = GenerateControlId(iRect);
            DragDropControlID = GUIUtility.GetControlID(DragAndDropHash, FocusType.Passive, iRect);
            
            // 当前Event
            var curEvent = Event.current;
            
            // 绘制标题
            var captionRect = iRect;
            captionRect.yMin += 2;
            captionRect.height = HeaderHeight;
            captionRect = DrawCaption(captionRect, curEvent, Caption);
            
            // 只读
            var lastEnable = GUI.enabled;
            if (ReadOnly)
            {
                GUI.enabled = false;
            }
            
            if (!Expandable || !IsExpanded)
            {
                GUI.enabled = lastEnable;
                return;
            }

            // 可分页
            var startPosY = captionRect.yMax;
            if (Pageable && null != Pagination)
            {
                var paginationRect = captionRect;
                paginationRect.yMin = startPosY;
                paginationRect.yMax = iRect.yMax;
                paginationRect = Pagination.Draw(paginationRect, curEvent);
            }
            else
            {
                // 可检索
                if (Searchable && ShowSearchBar)
                {
                    var searchBarRect = iRect;
                    searchBarRect.yMin = startPosY + 1;
                    searchBarRect.xMin += HorizontalSpacing;
                    searchBarRect.xMax -= HorizontalSpacing;
                    searchBarRect.height = SearchBarHeight;
                    searchBarRect = DrawSearchBar(searchBarRect, curEvent);
                    startPosY = searchBarRect.yMax;
                }
                
                // 绘制自身
                if (0 < VisibleChildCount)
                {
                    var selfBgRect = iRect;
                    selfBgRect.yMin = startPosY - 2;
                    selfBgRect.yMax -= 1;
                    selfBgRect.xMin += HorizontalSpacing;
                    selfBgRect.xMax -= HorizontalSpacing;
                    selfBgRect = DrawGenericBg(selfBgRect, curEvent);
                
                    var selfRect = selfBgRect;
                    selfRect.yMin = selfBgRect.yMin + 1;
                    selfRect.yMax -= (FooterHeight + 2);
                    selfRect = DrawSelf(selfRect, curEvent);

                    if (0.0f < FooterHeight)
                    {
                        var footerRect = selfRect;
                        footerRect.yMin = selfRect.yMax;
                        footerRect.yMax = footerRect.yMin + FooterHeight;
                        footerRect = DrawFooter(footerRect, curEvent);
                    }
                }
            }
            
            GUI.enabled = lastEnable;
            
            // 挂接所有事件
            if (lastEnable && 0 < VisibleChildCount)
            {
                HandleEvents(curEvent);
            }
        }

        /// <summary>
        /// 绘制GUI
        /// </summary>
        /// <param name="iRect">绘制矩形区域</param>
        /// <param name="iEvent">Event</param>
        /// <returns>绘制范围</returns>
        protected override Rect DrawSelf(Rect iRect, Event iEvent)
        {
            var displayRect = iRect;
            if (!IsExpanded) return displayRect;
                            
            var bodyBgRect = displayRect;
            bodyBgRect.xMin += HorizontalSpacing;
            bodyBgRect.xMax -= HorizontalSpacing;
            bodyBgRect.yMin = displayRect.yMin + 1;
            bodyBgRect.yMax -= 3;
            bodyBgRect = UtilsGUIEx.DrawGenericBg(bodyBgRect, iEvent);
            
            if (!IsArray)
            {
                var emptyDisplayRect = UtilsGUIEx.DrawLabel(bodyBgRect, iEvent, _emptyLabelContent, GuiExHelper.MiddleLeftLabel);
            }
            else if (0 >= VisibleSize)
            {
                if (Searching)
                {
                    _emptyLabelContent.text = "未检查到目标";
                }
                var emptyDisplayRect = UtilsGUIEx.DrawLabel(bodyBgRect, iEvent, _emptyLabelContent, GuiExHelper.MiddleLeftLabel);
            }
            else
            {
                var childrenRect = bodyBgRect;
                childrenRect.xMin += HorizontalSpacing;
                childrenRect.xMax -= 1;
                childrenRect.yMax -= VerticalSpacing;
                
                // 展开
                if (IsExpanded)
                {
                
                    // 选中多个
                    if (1 < ListSelection.Length) 
                    {
                        // 鼠标右击
                        if (EventType.ContextClick == iEvent.type && CanSelect(iEvent.mousePosition)) 
                        {
                            HandleMultipleRightClick(iEvent);
                        }
                    }

                    if (0 < VisibleSize)
                    {
                        childrenRect = DrawElements(childrenRect, iEvent, SelfProperty);
                    }
                }
            }
            return displayRect;
        }

        /// <summary>
        /// 绘制底部
        /// </summary>
        /// <param name="iRect"></param>
        /// <param name="iEvent"></param>
        /// <returns></returns>
        protected override Rect DrawFooter(Rect iRect, Event iEvent)
        {
            var displayRect = iRect;            
            
            var footerRect = displayRect;
            var startPosX = footerRect.xMax - BtnWidthIconOnly - HorizontalSpacing * 2;
            if (Removable)
            {
                footerRect.yMin = displayRect.yMin + 1;
                footerRect.yMax = displayRect.yMax - 1;
                var disabled = !Removable || 0 >= TotalSize;
                EditorGUI.BeginDisabledGroup(disabled);
                var delBtnRect = footerRect;
                delBtnRect.xMax -= HorizontalSpacing;
                delBtnRect.xMin = startPosX;
                delBtnRect = UtilsGUIEx.DrawFooterButton(delBtnRect, iEvent, GuiExHelper.DelIconBtn,
                    OnDelElementBtnClicked, GuiExHelper.PreButton);
                EditorGUI.EndDisabledGroup();
                startPosX = delBtnRect.xMin - BtnWidthIconOnly - HorizontalSpacing * 4;
            }

            if (Addable)
            {
                var addBtnRect = displayRect;
                addBtnRect.x = startPosX;
                addBtnRect = UtilsGUIEx.DrawFooterButton(addBtnRect, iEvent, GuiExHelper.AddIconBtn,
                    OnAddElementBtnClicked, GuiExHelper.PreButton);
            }

            return displayRect;
        }

        /// <summary>
        /// 绘制标题选项
        /// </summary>
        /// <param name="iRect">绘制矩形区域</param>
        /// <param name="iEvent">Event</param>
        /// <returns>绘制的矩形区域</returns>
        protected override Rect DrawCaptionOptions(Rect iRect, Event iEvent)
        {
            var displayRect = base.DrawCaptionOptions(iRect, iEvent);
            
            // 可排序
            var ascOrderRect = displayRect;
            if (Sortable)
            {
                var desOrderRect = displayRect;
                desOrderRect.xMax = displayRect.xMin - 1;
                desOrderRect.xMin = desOrderRect.xMax - BtnWidthIconOnly;
                // 排序 - 降序按钮 - 右上角最小化按钮
                if (GUI.Button(desOrderRect, GuiExHelper.SortDescending, GuiExHelper.PreButtonStretch)) 
                {
                    OnSortBtnClicked(true);
                }
                
                ascOrderRect = desOrderRect;
                ascOrderRect.xMax = desOrderRect.xMin - 1;
                ascOrderRect.xMin = ascOrderRect.xMax - BtnWidthIconOnly;
                // 排序 - 升序按钮 - 右上角最小化按钮
                if (GUI.Button(ascOrderRect, GuiExHelper.SortAscending, GuiExHelper.PreButtonStretch)) 
                {
                    OnSortBtnClicked(false);
                }
            }
            
            // 可检索
            var searchBtnRect = ascOrderRect;
            if (Searchable)
            {
                searchBtnRect.xMax = ascOrderRect.xMin - 1;
                searchBtnRect.xMin = searchBtnRect.xMax - BtnWidthIconOnly;
                // 检索按钮 - 右上角最小化按钮
                var searchBtnContent = ShowSearchBar ? SearchCancelIconBtnContent : SearchIconBtnContent;
                if (GUI.Button(searchBtnRect, searchBtnContent, GuiExHelper.PreButtonStretch))
                {
                    ShowSearchBar = !ShowSearchBar;
                    // 取消检索
                    if (!Pageable && !ShowSearchBar)
                    {
                        SearchResult = null;
                        Searching = false;
                        RefreshElementCaptions();
                    }
                }
            }

            return displayRect;
        }
        
#region SearchBar

        /// <summary>
        /// 绘制标题
        /// </summary>
        /// <param name="iRect">绘制矩形区域</param>
        /// <param name="iEvent">Event</param>
        /// <returns>绘制的矩形区域</returns>
        private Rect DrawSearchBar(Rect iRect, Event iEvent)
        {
            var displayRect = iRect;
            // 背景
            var bgRect = DrawGenericBg(displayRect, iEvent);

            var barRect = bgRect;
            barRect.xMin += HorizontalSpacing;
            barRect.xMax -= (HorizontalSpacing + _searchBtnWidth);
            barRect.yMin += 1;
            barRect.yMax -= 1;

            if (null == SearchBar)
            {
                SearchBar = new SearchField();
            }
            SearchKey = SearchBar.OnGUI(barRect, SearchKey);

            var searchBtnRect = barRect;
            searchBtnRect.xMin = barRect.xMax;
            searchBtnRect.xMax = bgRect.xMax - HorizontalSpacing;
            searchBtnRect = UtilsGUIEx.DrawButton(searchBtnRect, iEvent, SearchBtnContent,
                () =>
                {
                    ListSelection.Clear();
                    SearchResult = DoSearchByKey(SearchKey);
                    if (null != SearchResult && 0 < SearchResult.Count)
                    {
                        Searching = true;
                        if (Pageable)
                        {
                            Pagination?.ResetIndex();
                        }
                        ResetCaption();
                        RefreshElementCaptions();
                        ListSelection.Select(0);
                    }
                }, ColorEx.Chartreuse0);
            
            return displayRect;
        }

#endregion
        
#region Children

        /// <summary>
        /// 绘制子节点
        /// </summary>
        /// <param name="iRect">绘制矩形区域</param>
        /// <param name="iEvent">Event</param>
        /// <param name="iSelf">自身Property</param>
        /// <returns>绘制范围</returns>
        protected override Rect DrawElements(Rect iRect, Event iEvent, SerializedProperty iSelf)
        {
            return DrawElements(iRect, iEvent);
        }
        
        /// <summary>
        /// 绘制Element列表
        /// </summary>
        /// <param name="iRect">绘制矩形区域</param>
        /// <param name="iEvent">Event</param>
        /// <returns>绘制范围</returns>
        private Rect DrawElements(Rect iRect, Event iEvent)
        {
            var displayRect = iRect;
            
            if (!_dragging) {

                UpdateElementRects(displayRect, iEvent);
            }
            if (0 >= _elementRects.Length) return displayRect;
            if (!GetVisibleRange(out var oStartIndex, out var oEndIndex)) return displayRect;
                            
            var selectableRect = displayRect;
            selectableRect.yMin = _elementRects[oStartIndex].yMin;
            selectableRect.yMax = _elementRects[oEndIndex - 1].yMax;
                            
            HandlePreSelection(selectableRect, iEvent);
            var lastEnable = GUI.enabled;
            GUI.enabled = !ReadOnly;

            if (Searching)
            {
                for (var idx = oStartIndex; idx < oEndIndex; ++idx)
                {
                    var childCapsule = SearchResult[idx];
                    var elementCaption = GetElementCaption(idx, childCapsule.Target);
                    if(null == elementCaption) continue;

                    var childRect = _elementRects[idx];
                    var selected = ListSelection.Contains(idx);
                    //if(3 == idx && childProperty.isExpanded) continue;
                
                    childRect = DrawElement(childRect, iEvent, childCapsule.Target, idx, elementCaption, selected, selected);
                    childRect.y = childRect.yMax;
                }
            }
            else
            {
                for (var idx = oStartIndex; idx < oEndIndex; ++idx)
                {
                    var childProperty = ListProperty.GetArrayElementAtIndex(idx);
                    if(null == childProperty) continue;

                    var elementCaption = GetElementCaption(idx, childProperty);
                    if(null == elementCaption) continue;

                    var childRect = _elementRects[idx];
                    var selected = ListSelection.Contains(idx);
                    //if(3 == idx && childProperty.isExpanded) continue;
                
                    childRect = DrawElement(childRect, iEvent, childProperty, idx, elementCaption, selected, selected);
                    childRect.y = childRect.yMax;
                }
            }
                            
            GUI.enabled = lastEnable;
            HandlePostSelection(selectableRect, iEvent);
                            
            return displayRect;
        }

        /// <summary>
        /// 绘制Element
        /// </summary>
        /// <param name="iRect">绘制矩形区域</param>
        /// <param name="iEvent">Event</param>
        /// <param name="iElement">Element Property</param>
        /// <param name="iElementIndex">Element索引</param>
        /// <param name="iCaption">标题</param>
        /// <param name="iSelected">选中标志位</param>
        /// <param name="iFocused">焦点</param>
        /// <returns>绘制范围</returns>
        private Rect DrawElement(Rect iRect, Event iEvent, SerializedProperty iElement, int iElementIndex, 
            GUIContent iCaption, bool iSelected, bool iFocused)
        {
            var displayRect = iRect;
            
            // 可选中背景
            var bgRect = displayRect;
            var selectBgRect = displayRect;
            selectBgRect.yMax += 1;
            selectBgRect = UtilsGUIEx.DrawListElementBg(selectBgRect, iEvent, iSelected, iFocused);
            
            var dragMarkRect = displayRect;
            dragMarkRect.y = displayRect.yMin + VerticalSpacing;
            dragMarkRect.width = DragMarkWidth;
            dragMarkRect = UtilsGUIEx.DrawDragMark(dragMarkRect, iEvent);

            var captionRect = bgRect;
            captionRect.xMin = dragMarkRect.xMax + HorizontalSpacing;
            captionRect.xMin += HorizontalSpacing;
            captionRect.xMax -= 1;
            captionRect.y += 1;
            captionRect.height = HeaderHeight;
            if (iElement.hasVisibleChildren)
            {
                captionRect = UtilsGUIEx.DrawFoldout(captionRect, iEvent, iElement, iCaption, null,false);
                
                // 锁定
                var maxBtnRect = captionRect;
                var isElementLocked = IsElementLocked(iElementIndex);
                if (ElementLockable)
                {
                    var lockBtnRect = captionRect;
                    lockBtnRect.xMax = captionRect.xMax - HorizontalSpacing - 1;
                    lockBtnRect.xMin = lockBtnRect.xMax - BtnWidthIconOnly;
                    maxBtnRect.xMax = lockBtnRect.xMin - 1;
                    if (isElementLocked)
                    {
                        if (GUI.Button(lockBtnRect, LockIconBtnContent, GuiExHelper.PreButtonStretch))
                        {
                            SetElementLockState(iElementIndex, false);
                        }
                    }
                    else
                    {
                        if (GUI.Button(lockBtnRect, UnLockIconBtnContent, GuiExHelper.PreButtonStretch))
                        {
                            SetElementLockState(iElementIndex, true);
                        }
                    }
                }
                else
                {
                    maxBtnRect.xMax = captionRect.xMax - HorizontalSpacing - 1;
                }
                
                // 最大化
                maxBtnRect.xMin = maxBtnRect.xMax - BtnWidthIconOnly;
                if (GUI.Button(maxBtnRect, GuiExHelper.MaxWinBtn, GuiExHelper.PreButtonStretch)) 
                {
                    ExpandChildrenOfChild(iElement, true);
                }
                
                var minBtnRect = maxBtnRect;
                minBtnRect.xMax = maxBtnRect.xMin - 1;
                minBtnRect.xMin = minBtnRect.xMax - BtnWidthIconOnly;
            
                // 不展开按钮 - 右上角最小化按钮
                if (GUI.Button(minBtnRect, GuiExHelper.MinWinBtn, GuiExHelper.PreButtonStretch)) 
                {
                    ExpandChildrenOfChild(iElement, false);
                }
                
                // 展开
                if (iElement.isExpanded)
                {
                    var childBodyBgRect = bgRect;
                    childBodyBgRect.xMin = captionRect.xMin;
                    childBodyBgRect.xMax = captionRect.xMax;
                    childBodyBgRect.yMin = captionRect.yMax - 1;
                    childBodyBgRect.yMax -= 1;
                    childBodyBgRect = UtilsGUIEx.DrawGenericBg(childBodyBgRect, iEvent);
                    
                    var childDragMarkRect = childBodyBgRect;
                    childDragMarkRect.y = childBodyBgRect.yMin + VerticalSpacing;
                    childDragMarkRect.width = DragMarkWidth;
                    childDragMarkRect.height = SingleLineHeight;
                    childDragMarkRect = UtilsGUIEx.DrawDragMark(childDragMarkRect, iEvent);
                    
                    // 非数组元素
                    var copy = iElement.Copy();
                    var end = copy.GetEndProperty();
                    
                    var childChildRect = childBodyBgRect;
                    childChildRect.xMin = childDragMarkRect.xMax + VerticalSpacing;
                    childChildRect.xMax -= HorizontalSpacing;
                    childChildRect.yMin += VerticalSpacing;
                    childChildRect.height = SingleLineHeight;

                    var editable = !ReadOnly && !isElementLocked;
                    var lastEnable = GUI.enabled;
                    GUI.enabled = editable;
                    
                    var nextVisible = copy.NextVisible(true);
                    while (nextVisible && !SerializedProperty.EqualContents(copy, end)) 
                    {
                        //if (copy.hasVisibleChildren)
                        {
                            var copyHeight = EditorGUI.GetPropertyHeight(copy);
                            childChildRect.height = copyHeight;
                            childChildRect = UtilsGUIEx.DrawProperty(childChildRect, iEvent, copy, 
                                null, null, (int)GUIOperateOptions.DrawBg);
                            childChildRect.y = childChildRect.yMax + 1;
                        }
                        nextVisible = copy.NextVisible(false);
                    }
                    GUI.enabled = lastEnable;
                }
            }
            else
            {
                EditorGUI.PropertyField(captionRect, iElement);
            }
            
            return displayRect;
        }

#endregion

#endregion
        
    }
}
